//<<<+++OPENSOURCE
//<<<+++OPENSOURCE_LICENSE
/**
 * @addtogroup FPDFAPI
 * @{
 */

/**
 * @file
 * @brief Variable text processing.
 */

//<<<+++OPENSOURCE_MUST_BEGIN
#ifndef _FPDF_VT_H_
#define _FPDF_VT_H_
//<<<+++OPENSOURCE_MUST_END

#ifndef _FX_BASIC_H_
#include "../fxcrt/fx_basic.h"
#endif

#ifndef _FPDF_PARSER_
#include "../fpdfapi/fpdf_parser.h"
#endif

struct CPVT_WordPlace;
struct CPVT_WordRange;
struct CPVT_Word;
struct CPVT_Line;
struct CPVT_Section;

class IPDF_VariableText_Provider;
class IPDF_VariableText_Iterator;
class IPDF_VariableText;

/** @brief Word place structure. */
struct CPVT_WordPlace
{
	/** Default constructor. */
	CPVT_WordPlace() : nSecIndex(-1), nLineIndex(-1), nWordIndex(-1)
	{			
	}
	/**
	 * Construct a word place with parameters.
	 *
	 * @param[in] nSecIndex			Zero-based section index in the sections array.
	 * @param[in] nLineIndex		Zero-based line index in the section.
	 * @param[in] nWordIndex		Zero-based word index in the line.
	 */
	CPVT_WordPlace(FX_INT32 nSecIndex,FX_INT32 nLineIndex,FX_INT32 nWordIndex)
	{
		this->nSecIndex = nSecIndex;
		this->nLineIndex = nLineIndex;
		this->nWordIndex = nWordIndex;
	}

	/** Set to default. */
	void Default()
	{
		nSecIndex = nLineIndex = nWordIndex = -1;
	}

	/**
	 * comparison(==) operator overload.
	 *
	 * @param[in] wp		Ref to another word place.
	 * @return Non-zero means equal, otherwise not equal.
	 */
	FX_BOOL operator == (const CPVT_WordPlace & wp) const
	{
		return wp.nSecIndex == this->nSecIndex && wp.nLineIndex == this->nLineIndex && wp.nWordIndex == this->nWordIndex;
	}
	/**
	 * comparison(!=) operator overload.
	 *
	 * @param[in] wp		Ref to another word place.
	 * @return Non-zero means not equal, otherwise equal.
	 */
	FX_BOOL operator != (const CPVT_WordPlace & wp) const
	{
		return wp.nSecIndex != this->nSecIndex || wp.nLineIndex != this->nLineIndex || wp.nWordIndex != this->nWordIndex;
	}

	/**
	 * Compare the word place with another.
	 *
	 * @param[in] wp		Ref to another word place.
	 * @retval -1	The word place is before the another word place.
	 * @retval 0	The word place is equal the another word place.
	 * @retval 1	The word place is after the another word place.
	 */
	inline FX_INT32 WordCmp(const CPVT_WordPlace & wp) const
	{
		if (this->nSecIndex > wp.nSecIndex) return 1;
		if (this->nSecIndex < wp.nSecIndex) return -1;
		
		if (this->nLineIndex > wp.nLineIndex) return 1;
		if (this->nLineIndex < wp.nLineIndex) return -1;
		
		if (this->nWordIndex > wp.nWordIndex) return 1;		
		if (this->nWordIndex < wp.nWordIndex) return -1;

		return 0;
	}
	/**
	 * Compare the word line with another.
	 *
	 * @param[in] wp		Ref to another word place.
	 * @retval -1	The word line is before the another word line.
	 * @retval 0	The word line is equal the another word line.
	 * @retval 1	The word line is after the another word line.
	 */
	inline FX_INT32 LineCmp(const CPVT_WordPlace & wp) const
	{
		if (this->nSecIndex > wp.nSecIndex) return 1;
		if (this->nSecIndex < wp.nSecIndex) return -1;

		if (this->nLineIndex > wp.nLineIndex) return 1;
		if (this->nLineIndex < wp.nLineIndex) return -1;

		return 0;
	}
	/**
	 * Compare the word section with another.
	 *
	 * @param[in] wp		Ref to another word place.
	 * @retval -1	The word section is before the another word section.
	 * @retval 0	The word section is equal the another word section.
	 * @retval 1	The word section is after the another word section.
	 */
	inline FX_INT32 SecCmp(const CPVT_WordPlace & wp) const
	{
		if (this->nSecIndex > wp.nSecIndex) return 1;		
		if (this->nSecIndex < wp.nSecIndex) return -1;

		return 0;
	}

	/** The section index. */
	FX_INT32							nSecIndex;	
	/** The line index. */
	FX_INT32							nLineIndex;	
	/** The word index. */
	FX_INT32							nWordIndex;	
};

/** @brief Word range structure. */
struct CPVT_WordRange
{
	/** Default constructor. */
	CPVT_WordRange()
	{		
	}
	/**
	 * Construct with parameters.
	 *
	 * @param[in] begin			The begin word place.
	 * @param[in] end			The end word place.
	 */
	CPVT_WordRange(const CPVT_WordPlace & begin,const CPVT_WordPlace & end)
	{
		Set(begin,end);
	}

	/** Set to default. */
	void Default()
	{
		BeginPos.Default();
		EndPos.Default();
	}

	/**
	 * Change the word range.
	 *
	 * @param[in] begin			The new begin word place.
	 * @param[in] end			The new end word place.
	 */
	void Set(const CPVT_WordPlace & begin,const CPVT_WordPlace & end)
	{
		this->BeginPos = begin;
		this->EndPos = end;

		SwapWordPlace();
	}
	/**
	 * Change the begin word place and normalize the word range.
	 *
	 * @param[in] begin			The new begin word place.
	 */
	void SetBeginPos(const CPVT_WordPlace & begin)
	{
		this->BeginPos = begin;

		SwapWordPlace();
	}
	/**
	 * Change the end word place and normalize the word range.
	 *
	 * @param[in] end			The new end word place.
	 */
	void SetEndPos(const CPVT_WordPlace & end)
	{
		this->EndPos = end;

		SwapWordPlace();
	}

	/** Check whether the normalized word range contains words or not. */
	FX_BOOL IsExist() const
	{
		return this->BeginPos != this->EndPos;
	}

	/**
	 * comparison(!=) operator overload.
	 *
	 * @param[in] wr		Ref to another word range.
	 * @return Non-zero means not equal, otherwise equal.
	 */
	FX_BOOL operator != (const CPVT_WordRange & wr) const
	{
		return wr.BeginPos != this->BeginPos || wr.EndPos != this->EndPos;
	}

	/** Normalize the word range. */
	void SwapWordPlace()
	{
		if (BeginPos.WordCmp(EndPos) > 0)
		{
			CPVT_WordPlace place = EndPos;
			EndPos = BeginPos;
			BeginPos = place;
		}
	}

	/** The begin word place. */
	CPVT_WordPlace BeginPos;
	/** The end word place. */
	CPVT_WordPlace EndPos;
};

/** @brief Section property structure. */
struct CPVT_SecProps : public CFX_Object
{
	/** Default constructor. */
	CPVT_SecProps() : fLineLeading(0.0f), fLineIndent(0.0f), nAlignment(0)
	{
	}
	/**
	 * Construct with parameters.
	 *
	 * @param[in] lineLeading		The line leading. The spacing between baselines of consecutive lines of text.
	 * @param[in] lineIndent		The line indent. The distance from the edge to the line.
	 * @param[in] alignment			The alignment.	
	 */
	CPVT_SecProps(FX_FLOAT lineLeading, FX_FLOAT lineIndent, FX_INT32 alignment) : 
		fLineLeading(lineLeading), fLineIndent(lineIndent), nAlignment(alignment)
	{
	}
	/** Copy constructor. */
	CPVT_SecProps(const CPVT_SecProps & other) : 
		fLineLeading(other.fLineLeading), fLineIndent(other.fLineIndent), nAlignment(other.nAlignment)
	{
	}

	/** The line leading. */
	FX_FLOAT			fLineLeading;
	/** The line indent. */
	FX_FLOAT			fLineIndent;
	/** The alignment. 0: Left-justified; 1: Centered; 2: Right-justified. */
	FX_INT32			nAlignment;
};

/** @brief Word property structure. */
struct CPVT_WordProps : public CFX_Object
{
	/** Default constructor. */
	CPVT_WordProps() : nFontIndex(-1), fFontSize(0.0f), dwWordColor(0), nScriptType(0), nWordStyle(0), 
		fCharSpace(0.0f), nHorzScale(0)
	{
	}
	/**
	 * Construct with parameters.
	 *
	 * @param[in] fontIndex		The font index.
	 * @param[in] fontSize		The font size.
	 * @param[in] wordColor		The word color.
	 * @param[in] scriptType	The script type. such as subscript, superscript...
	 * @param[in] wordStyle		The word style. such as bold, italic, underline...etc.
	 * @param[in] charSpace		The character space.
	 * @param[in] horzScale		The horizontal scaling.
	 */
	CPVT_WordProps(FX_INT32	fontIndex, FX_FLOAT fontSize, FX_COLORREF wordColor = 0, FX_INT32 scriptType = 0, FX_INT32 wordStyle = 0,
		FX_FLOAT charSpace = 0, FX_INT32 horzScale = 100) :
			nFontIndex(fontIndex), fFontSize(fontSize), dwWordColor(wordColor), nScriptType(scriptType), 
				nWordStyle(wordStyle), fCharSpace(charSpace), nHorzScale(horzScale)
	{
	}
	/** Copy constructor. */
	CPVT_WordProps(const CPVT_WordProps & other) :
			nFontIndex(other.nFontIndex), fFontSize(other.fFontSize), dwWordColor(other.dwWordColor),
				nScriptType(other.nScriptType), nWordStyle(other.nWordStyle), fCharSpace(other.fCharSpace),
				nHorzScale(other.nHorzScale)
	{
	}

	/** The font index. */
	FX_INT32					nFontIndex;
	/** The font size. */
	FX_FLOAT					fFontSize;
	/** The word color. */
	FX_COLORREF					dwWordColor;
	/** The script type. */
	FX_INT32					nScriptType;
	/** The word style. */
	FX_INT32					nWordStyle;
	/** The character spacing. */
	FX_FLOAT					fCharSpace;
	/** The horizontal scaling. */
	FX_INT32					nHorzScale;
};

/** @brief Word class. */
struct CPVT_Word
{
	/** Default constructor. */
	CPVT_Word() : Word(0), nCharset(0), ptWord(0,0), fAscent(0.0f), fDescent(0.0f), fWidth(0.0f),
		fFontSize(0), WordProps()
	{
	}

	/** The character code. */
	FX_WORD						Word;
	/** The character set. */
	FX_INT32					nCharset;
	/** The word place. */
	CPVT_WordPlace				WordPlace;
	/** The word's origin position. */
	CPDF_Point					ptWord;
	/** The word ascent. */
	FX_FLOAT					fAscent;
	/** The word descent. */
	FX_FLOAT					fDescent;
	/** The word width. */
	FX_FLOAT					fWidth;
	/** The font index. */
	FX_INT32					nFontIndex;
	/** The font size. */
	FX_FLOAT					fFontSize;
	/** The word property. */
	CPVT_WordProps				WordProps;
};

/** @brief Line class. */
struct CPVT_Line
{
	/** Default constructor. */
	CPVT_Line() : ptLine(0,0), fLineWidth(0.0f), fLineAscent(0.0f), fLineDescent(0.0f)
	{
	}

	/** The start word place. */
	CPVT_WordPlace				lineplace;
	/** The end word place. */ 
	CPVT_WordPlace				lineEnd;
	/** The line's origin position. */
	CPDF_Point					ptLine;	
	/** The line width. */
	FX_FLOAT					fLineWidth;
	/** The line ascent. */
	FX_FLOAT					fLineAscent;
	/** The line descent. */
	FX_FLOAT					fLineDescent;
};

/** @brief Section class. */
struct CPVT_Section
{
	/** The start word place. */
	CPVT_WordPlace				secplace;
	/** The section rectangle. */
	CPDF_Rect					rcSection;
	/** The section property. */
	CPVT_SecProps				SecProps;
	/** The word property. */
	CPVT_WordProps				WordProps;
};

/** @brief Variable text provider. */
class IPDF_VariableText_Provider
{
public:
	/**
	 * Get the width of a character, in font coordinate.
	 *
	 * @param[in] nFontIndex		The font index.
	 * @param[in] word				The word code.
	 * @param[in] nWordStyle		The word style.
	 * @return The width of the character, in font coordinate.
	 */
	virtual FX_INT32						GetCharWidth(FX_INT32 nFontIndex, FX_WORD word, FX_INT32 nWordStyle) = 0;

	/**
	 * Get the ascent of a font, in font coordinate.
	 *
	 * @param[in] nFontIndex		The font index.
	 * @return The font ascent.
	 */
	virtual FX_INT32						GetTypeAscent(FX_INT32 nFontIndex) = 0;
	/**
	 * Get the descent of a font, in font coordinate.
	 *
	 * @param[in] nFontIndex		The font index.
	 * @return The font descent.
	 */
	virtual FX_INT32						GetTypeDescent(FX_INT32 nFontIndex) = 0;

	/** get the index of a font that can show a word. */
	virtual FX_INT32						GetWordFontIndex(FX_WORD word, FX_INT32 charset, FX_INT32 nFontIndex) = 0;

	/** the word is latin word? */
	virtual FX_BOOL							IsLatinWord(FX_WORD word) = 0;

	/** get the default index of a font. */
	virtual FX_INT32						GetDefaultFontIndex() = 0;
};

/** @brief Variable text iterator. */
class IPDF_VariableText_Iterator
{
public:
	/** goto the next word position. */
	virtual FX_BOOL							NextWord() = 0;

	/** goto the previous word position. */
	virtual FX_BOOL							PrevWord() = 0;

	/** goto the next line position. */
	virtual FX_BOOL							NextLine() = 0;

	/** goto the previous line position. */
	virtual FX_BOOL							PrevLine() = 0;

	/** goto the next section position. */
	virtual FX_BOOL							NextSection() = 0;

	/** goto the previous section position. */
	virtual FX_BOOL							PrevSection() = 0;

	/** get current word information. */
	virtual FX_BOOL							GetWord(CPVT_Word & word) const = 0;

	/** set current word information. */
	virtual FX_BOOL							SetWord(const CPVT_Word & word) = 0;

	/** get current line information. */
	virtual FX_BOOL							GetLine(CPVT_Line & line) const = 0;

	/** get current section information. */
	virtual FX_BOOL							GetSection(CPVT_Section & section) const = 0;

	/** set current section information. */
	virtual	FX_BOOL							SetSection(const CPVT_Section & section) = 0;

	/** set the current word position. */
	virtual void							SetAt(FX_INT32 nWordIndex) = 0;

	/** set the current word position. */
	virtual void							SetAt(const CPVT_WordPlace & place) = 0;

	/** get the current word position. */
	virtual const CPVT_WordPlace &			GetAt() const = 0;
};

/** @brief Variable text class. */
class IPDF_VariableText
{
public:
	/** Create an empty variable text. */
	static IPDF_VariableText*			NewVariableText();
	/** Delete a variable text. */
	static void							DelVariableText(IPDF_VariableText* pVT);

public:	
	/** set a IPDF_VariableText_Provider pointer implemented by user, and return the old pointer. */
	virtual IPDF_VariableText_Provider*		SetProvider(IPDF_VariableText_Provider * pProvider) = 0;
	/** get a pointer allocated by VT, by this pointer, user can iterate the contents of VT, but don't need to release. */
	virtual IPDF_VariableText_Iterator*		GetIterator() = 0;

	/** set the bounding box of the text area. */
	virtual void							SetPlateRect(const CPDF_Rect & rect) = 0;

	/** set the text alignment , nFormat (0:left;1:middle;2:right). */
	virtual void							SetAlignment(FX_INT32 nFormat = 0) = 0;

	/** if the text is shown in secret , set a character for substitute. */
	virtual void							SetPasswordChar(FX_WORD wSubWord = '*') = 0;

	/** set the maximal count of words of the text. */
	virtual void							SetLimitChar(FX_INT32 nLimitChar = 0) = 0;

	/** if set the count of charArray , then all words is shown in equal space. */
	virtual void							SetCharArray(FX_INT32 nCharArray = 0) = 0;

	/** set the space of two characters. */
	virtual void							SetCharSpace(FX_FLOAT fCharSpace = 0.0f) = 0;

	/** set the horizontal scale of all characters. */
	virtual void							SetHorzScale(FX_INT32 nHorzScale = 100) = 0;

	/** if set, CRLF is allowed. */
	virtual void							SetMultiLine(FX_BOOL bMultiLine = TRUE) = 0;

	/** if set, all words auto fit the width of the bounding box. */
	virtual void							SetAutoReturn(FX_BOOL bAuto = TRUE) = 0;

	/** if set, a font size is calculated to full fit the bounding box. */
	virtual void							SetAutoFontSize(FX_BOOL bAuto = TRUE) = 0;

	/** set the font size of all words. */
	virtual void							SetFontSize(FX_FLOAT fFontSize) = 0;

	/** set the line leading of all lines. */
	virtual void							SetLineLeading(FX_FLOAT fLineLeading) = 0;

	/** if set, all words is shown in rich text format. */
	virtual void							SetRichText(FX_BOOL bRichText) = 0;


	/** Initialize the text , the method must called before other methods. */
	virtual void							Initialize() = 0;

	/** is the text is initialized? */
	virtual FX_BOOL							IsValid() const = 0;

	/** is the rich text edit? */
	virtual FX_BOOL							IsRichText() const = 0;

	/** rearrange the position of all words. */
	virtual void							RearrangeAll() = 0;

	/** rearrange the position of specific word range. */
	virtual void							RearrangePart(const CPVT_WordRange & PlaceRange) = 0;


	/** empty the content of VT. */
	virtual void							ResetAll() = 0;

	/** put text into VT. */
	virtual void							SetText(FX_LPCWSTR text, FX_INT32 charset = 1, const CPVT_SecProps * pSecProps = NULL,
												const CPVT_WordProps * pWordProps = NULL) = 0;

	/** insert a word in specific position. */
	virtual CPVT_WordPlace					InsertWord(const CPVT_WordPlace & place,FX_WORD word, FX_INT32 charset = 1,
													const CPVT_WordProps * pWordProps = NULL) = 0;

	/** insert a section in specific position. */
	virtual CPVT_WordPlace					InsertSection(const CPVT_WordPlace & place, const CPVT_SecProps * pSecProps = NULL,
												const CPVT_WordProps * pWordProps = NULL) = 0;

	/** insert text in specific position. */
	virtual CPVT_WordPlace					InsertText(const CPVT_WordPlace & place,FX_LPCWSTR text, FX_INT32 charset = 1,
													const CPVT_SecProps * pSecProps = NULL,	const CPVT_WordProps * pWordProps = NULL) = 0;

	/** delete words in specific range. */
	virtual CPVT_WordPlace					DeleteWords(const CPVT_WordRange & PlaceRange) = 0;

	/** delete a word in specific position. */
	virtual CPVT_WordPlace					DeleteWord(const CPVT_WordPlace & place) = 0;

	/** backspace a word in specific position. */
	virtual CPVT_WordPlace					BackSpaceWord(const CPVT_WordPlace & place) = 0;

	/** get the bounding box of VT. */
	virtual const CPDF_Rect &				GetPlateRect() const = 0;

	/** get the fact area of text. */
	virtual CPDF_Rect						GetContentRect() const = 0;

	/** get the count of all words. */
	virtual FX_INT32						GetTotalWords() const = 0;

	/** get the fontsize of all words , if richtext flag is't setted. */
	virtual FX_FLOAT						GetFontSize() const = 0;

	/** get the text alignment , return value (0:left;1:middle;2:right). */
	virtual FX_INT32						GetAlignment() const = 0;

	/** get the character for mask all words. */
	virtual FX_WORD							GetPasswordChar() const = 0;

	/** get the count of charArray. */
	virtual FX_INT32						GetCharArray() const = 0;

	/** get the maximal count of words of the text. */
	virtual FX_INT32						GetLimitChar() const = 0;

	/** is CRLF is allowed? */
	virtual FX_BOOL							IsMultiLine() const = 0;

	/** get the horizontal scale of all characters. */
	virtual FX_INT32						GetHorzScale() const = 0;

	/** get the space of two characters. */
	virtual FX_FLOAT						GetCharSpace() const = 0;

	/** get the first position of text. */
	virtual CPVT_WordPlace					GetBeginWordPlace() const = 0;

	/** get the last position of text. */
	virtual CPVT_WordPlace					GetEndWordPlace() const = 0;	

	/** get the previous position of specific word position. */
	virtual CPVT_WordPlace					GetPrevWordPlace(const CPVT_WordPlace & place) const = 0;

	/** get the next position of specific word position. */
	virtual CPVT_WordPlace					GetNextWordPlace(const CPVT_WordPlace & place) const = 0;

	/** search a word position by a point. */
	virtual CPVT_WordPlace					SearchWordPlace(const CPDF_Point & point) const = 0;

	/** get the up position of specific word position. */
	virtual CPVT_WordPlace					GetUpWordPlace(const CPVT_WordPlace & place,const CPDF_Point & point) const = 0;

	/** get the down position of specific word position. */
	virtual CPVT_WordPlace					GetDownWordPlace(const CPVT_WordPlace & place,const CPDF_Point & point) const = 0;

	/** get the beginning position of a line. */
	virtual CPVT_WordPlace					GetLineBeginPlace(const CPVT_WordPlace & place) const = 0;

	/** get the ending position of a line. */
	virtual CPVT_WordPlace					GetLineEndPlace(const CPVT_WordPlace & place) const = 0;

	/** get the beginning position of a section. */
	virtual CPVT_WordPlace					GetSectionBeginPlace(const CPVT_WordPlace & place) const = 0;

	/** get the ending position of a section. */
	virtual CPVT_WordPlace					GetSectionEndPlace(const CPVT_WordPlace & place) const = 0;


	/** if text is rearranged , you must update the old word position. */
	virtual void							UpdateWordPlace(CPVT_WordPlace & place) const = 0;

	/**
	 * if the place is the beginning position of a line and not the beginning position of a section,
	 * you can get the previous place or the next place.
	 */
	virtual CPVT_WordPlace					AjustLineHeader(const CPVT_WordPlace & place,FX_BOOL bPrevOrNext) const = 0;

	/** convert a word place to a word index. */
	virtual FX_INT32						WordPlaceToWordIndex(const CPVT_WordPlace & place) const = 0;
	/** convert a word index to a word place. */
	virtual CPVT_WordPlace					WordIndexToWordPlace(FX_INT32 index) const = 0;
};

//<<<+++OPENSOURCE_MUST_BEGIN
#endif //_FPDF_VT_H_
//<<<+++OPENSOURCE_MUST_END

/** @} */
